package com.xiaof.store.controller;

import com.xiaof.store.controller.ex.*;
import com.xiaof.store.entity.User;
import com.xiaof.store.service.IUserService;
import com.xiaof.store.service.ex.InsertException;
import com.xiaof.store.service.ex.UsernameDuplicateException;
import com.xiaof.store.util.JsonResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * Created with IntelliJ IDEA.
 *
 * @ProjectName: store
 * @Package: com.xiaof.store.controller
 * @ClassName: UserController
 * @Author: xiaof
 * @Description:
 * @Date: 2021/12/21 10:44
 * @Version: 1.0
 */
@RestController//数据以json格式返回
@RequestMapping("/users")
public class UserController extends BaseController{
    @Autowired
    private IUserService userService;

    /**
     * 1.接收数据方式:请求处理方法的参数列表设置为pojo类型来接收前端的数据，
     * SpringBoot会将前端的url地址中的参数名和
     * pojo类的属性名进行比较，如果这两个名称项目，则将值注入到pojo类中对应的属性上
     */
    @RequestMapping("reg")
    public JsonResult reg(User user) {
        userService.reg(user);
        return new JsonResult<>(OK);
    }
    /*private JsonResult reg(User user){
        JsonResult<Void> result=new JsonResult<>();
        try {
            userService.reg(user);
            result.setState(200);
            result.setMessage("用户注册成功");
        } catch (UsernameDuplicateException e) {
            result.setState(4000);
            result.setMessage("用户名被占用");
        }catch (InsertException e){
            result.setState(5000);
            result.setMessage("注册时产生未知异常");
        }
        return result;
    }*/

    /**
     * 2.接收数据方式:请求处理方法的参数列表设置为非pojo类型
     * SpringBoot会直接将请求的参数名和方法的参数名直接进行比较，如果名称相同则自动完成值的依赖注入
     */
    //3.在登录的方法中将数据封装在session对象中。
    // 服务本身自动创建有session对象，已经是一个全局的session对象。
    // SpringBoot直接使用session对象，直接将HttpSession类型的的对象做为请求处理方法的参数
    // 会自动将全局的session对象注入到请求处理方法的session形参上。|

    @RequestMapping("login")
    public JsonResult<User> login(String username,
                            String password,
                            HttpSession session){
        User data = userService.login(username, password);
        //向session对象中绑定值(session是全局的)
        session.setAttribute("uid",data.getUid());
        session.setAttribute("username",data.getUsername());
        //System.out.println(getUidFromSession(session));
        //System.out.println(getUsernameFromSession(session));
        return new JsonResult<User>(OK,data);
    }
    @RequestMapping("change_password")
    public JsonResult<Void> changePassword(HttpSession session,
                                           String oldPassword,
                                           String newPassword){
        // 调用session.getAttribute("")获取uid和username
        Integer uid = getUidFromSession(session);
        String username = getUsernameFromSession(session);
        // 调用业务对象执行修改密码
        userService.changePassword(uid,username,oldPassword,newPassword);
        // 返回成功
        return new JsonResult(OK);

    }
    @GetMapping("get_by_uid")
    public JsonResult<User> getByUid(HttpSession session) {
        // 从HttpSession对象中获取uid
        Integer uid = getUidFromSession(session);
        // 调用业务对象执行获取数据
        User data = userService.getByUid(uid);
        // 响应成功和数据
        return new JsonResult<User>(OK, data);
    }
    @RequestMapping("change_info")
    public JsonResult<Void> changeInfo(User user, HttpSession session) {
        // 从HttpSession对象中获取uid和username
        Integer uid = getUidFromSession(session);
        String username = getUsernameFromSession(session);
        // 调用业务对象执行修改用户资料
        userService.changeInfo(uid, username, user);
        // 响应成功
        return new JsonResult<Void>(OK);
    }
    /** 头像文件大小的上限值(10MB) */
    public static final int AVATAR_MAX_SIZE = 10 * 1024 * 1024;
    /** 允许上传的头像的文件类型 */
    public static final List<String> AVATAR_TYPES = new ArrayList<String>();

    /** 初始化允许上传的头像的文件类型 */
    static {
        AVATAR_TYPES.add("image/jpeg");
        AVATAR_TYPES.add("image/png");
        AVATAR_TYPES.add("image/bmp");
        AVATAR_TYPES.add("image/gif");
    }


    /**
     * MultipartFile是SpringMVC提供的接口，用来接收文件，
     * 只需要在参数列表上声明一个MultipartFile类型的参数，然后SpringBoot自动将传递给服务的文件数据赋值赋值给这个参数
     *
     * @RequestParam表示请求中的参数，将请求中的参数注入请求处理方法的某个参数上，
     * 如果名称不一致则可以使用@RequestParam注解进行标记和映射
     * @param session
     * @param file
     * @return
     */
    @RequestMapping("change_avatar")
    public JsonResult<String> changeAvatar(HttpSession session, @RequestParam("file") MultipartFile file) {

        // 判断上传的文件是否为空
        if (file.isEmpty()) {
            // 是：抛出异常
            throw new FileEmptyException("上传的头像文件不允许为空");
        }

        // 判断上传的文件大小是否超出限制值
        if (file.getSize() > AVATAR_MAX_SIZE) { // getSize()：返回文件的大小，以字节为单位
            // 是：抛出异常
            throw new FileSizeException("不允许上传超过" + (AVATAR_MAX_SIZE / 1024) + "KB的头像文件");
        }

        // 判断上传的文件类型是否超出限制
        String contentType = file.getContentType();
        // boolean contains(Object o)：当前列表若包含某元素，返回结果为true；若不包含该元素，返回结果为false
        if (!AVATAR_TYPES.contains(contentType)) {
            // 是：抛出异常
            throw new FileTypeException("不支持使用该类型的文件作为头像，允许的文件类型：" + AVATAR_TYPES);
        }
        // 获取当前项目的绝对磁盘路径，上传的文件存到upload目录下
        String parent = session.getServletContext().getRealPath("upload");
        System.out.println(parent);
        // 保存头像文件的文件夹
        //用file指向这个路径，file是否存在
        File dir = new File(parent);
        if (!dir.exists()) {//检测目录是否存在
            dir.mkdirs();//创建当前的目录
        }
        //获取文件名，使用UUID生成随机串替代文件名字，因为相同的文件名会直接覆盖
        String originalFilename = file.getOriginalFilename();
        System.out.println("filename："+originalFilename);
        //获取文件名以“.”分割的位置
        int index = originalFilename.lastIndexOf(".");
        //保存后缀
        String suffix=originalFilename.substring(index);
        /*String suffix = "";
        String originalFilename = file.getOriginalFilename();
        int beginIndex = originalFilename.lastIndexOf(".");
        if (beginIndex > 0) {
            suffix = originalFilename.substring(beginIndex);
        }*/
        //使用UUID后的生成的完整的文件名ASDSDXS.png
        String filename = UUID.randomUUID().toString().toUpperCase()+ suffix;
        // 创建文件对象，表示保存的头像文件,此时是一个空文件，后续将文件数据写入该文件
        File dest = new File(dir, filename);
        try {
            file.transferTo(dest);//将参数（file）中的数据写入到目标文件中
        } catch (FileStateException e){
            throw new FileStateException("文件状态异常，可能文件已被移动或删除");
        }
        catch (IOException e) {
            throw new FileUploadIOException("文件读写异常");
        }
        // 头像路径
        String avatar = "/upload/" + filename;
        // 从Session中获取uid和username
        Integer uid = getUidFromSession(session);
        String username = getUsernameFromSession(session);
        // 将头像写入到数据库中
        userService.changeAvatar(uid, username, avatar);

        // 返回用户头像的路径给前端页面，将来用于头像展示使用
        return new JsonResult<String>(OK, avatar);
    }
}
